// SyncQueue.h: interface for the SyncQueue class.
//
//////////////////////////////////////////////////////////////////////

#ifndef SYNCQUEUE_H
#define SYNCQUEUE_H

#include "Mutex.h"
#include <list>
#include <pthread.h>
#include <semaphore.h>

template<class E>
class SyncQueue
{
public:
    SyncQueue();
    ~SyncQueue();
    
    //Add one element at the tail
    bool Append( const E& e );
    //Add on element at the beginning
    bool Push_front(const E& e);
    //remove one element from front
    bool RemoveHead( E& pe, uint seconds_timeout);
    //test if empty
    bool Empty();
    int GetSize();
    void CleanUp();

private:
    CMutexLock m_Mutex;
    CConditionVariable m_NotEmpty;
    std::list<E> m_buffer;
};

template<class E>
SyncQueue<E>::SyncQueue()
: m_Mutex(), m_NotEmpty(m_Mutex), m_buffer()
{
}

template<class E>
SyncQueue<E>::~SyncQueue()
{
}

template<class E>
bool SyncQueue<E>::Append( const E& pe)
{
    CSynchronizeAccess Lock(m_Mutex);
    m_buffer.push_back( pe );
    m_NotEmpty.Notify();

    return true;
}

template<class E>
bool SyncQueue<E>::Push_front(const E& pe)
{
    CSynchronizeAccess Lock(m_Mutex);
    m_buffer.push_front( pe );
    m_NotEmpty.Notify();

    return true;
}

template<class E>
bool SyncQueue<E>::RemoveHead( E& pe, uint seconds_timeout)
{
    CSynchronizeAccess Lock(m_Mutex);
    while (m_buffer.empty())
    {
        if(m_NotEmpty.WaitForSeconds(seconds_timeout)) //if timeout, return
            return false;
    }
    assert(!m_buffer.empty());

    pe = m_buffer.front();
    m_buffer.pop_front();

    return true;
}

template<class E>
bool SyncQueue<E>::Empty()
{
    CSynchronizeAccess Lock(m_Mutex);
    return m_buffer.empty();
}

template<class E>
int SyncQueue<E>::GetSize()
{
    CSynchronizeAccess Lock(m_Mutex);
    return m_buffer.size();
}

template<class E>
void SyncQueue<E>::CleanUp()
{
    CSynchronizeAccess Lock(m_Mutex);
    m_buffer.clear();
}
#endif
